package com.unitedats.common.util;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;


@Transactional
@Repository
public class DBManager {
	@PersistenceContext(unitName = "uts")
	private EntityManager entityManager;

	protected EntityManager getEntityManager() {
		return this.entityManager;
	}

	public EntityTransaction beginTransaction() {
		final EntityTransaction entityTransaction = entityManager.getTransaction();
		if (!entityTransaction.isActive())
			entityTransaction.begin();
		return entityTransaction;
	}

	public void commitTransaction(final EntityTransaction entityTransaction) {
		if (!entityTransaction.isActive())
			entityTransaction.begin();
		entityTransaction.commit();
	}

	public void rollbackTransaction(final EntityTransaction entityTransaction) {
		entityTransaction.rollback();
	}

	public List executeNativeQueryForSearch(String sqlString, Class c, HashMap<Integer, Object> map) {
		Query q = (c == null) ? entityManager.createNativeQuery(sqlString) : entityManager.createNativeQuery(sqlString,
				c);
		if (map != null)
			for (int key : map.keySet())
				q.setParameter(key, map.get(key));
		Common.log(q.toString());
		return q.getResultList();
	}

	public List executeNativeQueryForSearch(String sqlString, HashMap<Integer, Object> map) {
		return executeNativeQueryForSearch(sqlString, null, map);
	}

	public int executeNativeQueryForUpdate(String sqlString, HashMap<Integer, Object> map) {
		Query q = entityManager.createNativeQuery(sqlString);
		// EntityTransaction trans = em.getTransaction();
		// trans.begin();
		if (map != null)
			for (int key : map.keySet())
				q.setParameter(key, map.get(key));
		Common.log(q.toString());
		return q.executeUpdate();
	}

	/*
	 * for paging
	 */
	public Object queryByRange(String jpqlStmt, int firstResult, int maxResults) {
		Query query = entityManager.createQuery(jpqlStmt);
		if (firstResult > 0) {
			query = query.setFirstResult(firstResult);
		}
		if (maxResults > 0) {
			query = query.setMaxResults(maxResults);
		}
		return query.getResultList();
	}

	public <T> List<T> queryJPQL(String jpqlStmt, Map<Integer, Object> map, Class<T> c) {
		Common.log("queryJPQL::jpqlStmt:"+jpqlStmt);
		TypedQuery<T> q = entityManager.createQuery(jpqlStmt, c);
		if (map != null)
			for (Integer key : map.keySet())
				q.setParameter(key, map.get(key));
		return q.getResultList();
	}

	public <T> T persistEntity(T entity) {
		entityManager.persist(entity);
		return entity;
	}

	public <T> T findById(int id, Class<T> c) {
		T entity = entityManager.find(c, id);
		return entity;
	}

	public <T> T findById(Object id, Class<T> c) {
		T entity = entityManager.find(c, id);
		return entity;
	}

	public void deleteEntity(Object entity) {
		// entity = find(entity).get(0);
		entityManager.remove(entityManager.merge(entity));
		entity=null;
//		return entity;
	}

	public <T> T mergeEntity(T entity) {
		// entityManager.setFlushMode(FlushModeType.AUTO);
		// EntityTransaction et=beginTransaction();
		entity = entityManager.merge(entity);
		// commitTransaction(et);
		return entity;
	}

	public List findAll(Class c) {
		return entityManager.createNamedQuery(c.getSimpleName() + ".findAll").getResultList();
	}
	
	public List executeNamedQuery(Class c, String namedQuery) {
		return entityManager.createNamedQuery(c.getSimpleName() + "." + namedQuery).getResultList();
	}

	public <T> List<T> find(T beanType, Map<String, Map<DynamicQueryBuilder.Operator, Object>> advancedParams,
			Map<String, Boolean> orderBy, DynamicQueryBuilder.Operator.OperType operType) {

		DynamicQueryBuilder dyncQueryBuilder = new DynamicQueryBuilder.Builder(entityManager).select(beanType)
				.withOperType(operType).orderBy(orderBy).withAdvancedParams(advancedParams).build();

		Common.log(dyncQueryBuilder.getQueryString());
		return dyncQueryBuilder.getQuery().getResultList();
	}

	public <T> List<T> find(T beanType, Map<String, Map<DynamicQueryBuilder.Operator, Object>> advancedParams,
			Map<String, Boolean> orderBy) {

		DynamicQueryBuilder dyncQueryBuilder = new DynamicQueryBuilder.Builder(entityManager).select(beanType)
				.withOperType(DynamicQueryBuilder.Operator.OperType.AND).orderBy(orderBy)
				.withAdvancedParams(advancedParams).build();

		Common.log("------------------------" + dyncQueryBuilder.getQueryString());
		return dyncQueryBuilder.getQuery().getResultList();
	}

	public <T> List<T> find(T beanType, Map<String, Boolean> orderBy, DynamicQueryBuilder.Operator.OperType operType) {

		DynamicQueryBuilder dyncQueryBuilder = new DynamicQueryBuilder.Builder(entityManager).select(beanType)
				.withOperType(operType).orderBy(orderBy).build();

		Common.log(dyncQueryBuilder.getQueryString());
		List<T> list = dyncQueryBuilder.getQuery().getResultList();
		return list;
	}

	public <T> List<T> find(T beanType, Map<String, Boolean> orderBy) {

		DynamicQueryBuilder dyncQueryBuilder = new DynamicQueryBuilder.Builder(entityManager).select(beanType)
				.withOperType(DynamicQueryBuilder.Operator.OperType.AND).orderBy(orderBy).build();

		Common.log(dyncQueryBuilder.getQueryString());
		return dyncQueryBuilder.getQuery().getResultList();
	}

	public <T> List<T> find(T beanType, DynamicQueryBuilder.Operator.OperType operType) {

		DynamicQueryBuilder dyncQueryBuilder = new DynamicQueryBuilder.Builder(entityManager).select(beanType)
				.withOperType(operType).build();

		Common.log(dyncQueryBuilder.getQueryString());
		return dyncQueryBuilder.getQuery().getResultList();
	}

	public <T> List<T> find(T beanType) {

		DynamicQueryBuilder dyncQueryBuilder = new DynamicQueryBuilder.Builder(entityManager).select(beanType)
				.withOperType(DynamicQueryBuilder.Operator.OperType.AND).build();

		Common.log("search query::" + dyncQueryBuilder.getQueryString());
		List<T> list = dyncQueryBuilder.getQuery().getResultList();
		return list;
	}

	public DynamicQueryBuilder getDynamicQueryBuilder(Object beanType) {
		// DynamicQueryBuilder<T> dynamicQueryBuilder=new
		// DynamicQueryBuilder.Builder(entityManager).select(beanType);
		return new DynamicQueryBuilder.Builder(entityManager).select(beanType).build();

	}

	public <T> List<T> find(T beanType, DynamicQueryBuilder dyncQueryBuilder) {
		Common.log("search query::" + dyncQueryBuilder.getQueryString());
		List<T> list = dyncQueryBuilder.getQuery().getResultList();
		return list;
	}

	public void destory() {
		// if (em != null)
		// em.close();
	}

	public static void main(String[] args) {
		String updateQuery = "insert into user (name,password) values (?,SHA1(?))";
		// String updateQuery =
		// "insert into user (name,password) values ('islam',SHA(:pass))";

		// String updateQuery =
		// "insert into user (name,password) values ('islam',SHA('123'))";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"D:\\Awad\\work\\mmp\\MMPHibernate\\src\\main\\webapp\\WEB-INF\\applicationContext.xml");

		HashMap<Integer, Object> map = new HashMap<Integer, Object>();
		map.put(1, "Islam");
		map.put(2, "123");
		// EntityTransaction t = m.beginTransaction();
//		DBManagerFactory.getInstance().executeNativeQueryForUpdate(updateQuery, map);
		// m.commitTransaction(t);
	}

}
